﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Utilities;
using Microsoft.VisualStudio.Text.Tagging;
using LuaLanguage;
using PSLib.CodeFormating.Lexems;

namespace LuaLanguageExtension
{
    [Export(typeof(ITaggerProvider))]
    [ContentType("LuaLanguageExtension")]
    [TagType(typeof(ClassificationTag))]
    internal sealed class LuaClassifierProvider : ITaggerProvider
    {

        [Export]
        [Name("LuaLanguageExtension")]
        [BaseDefinition("code")]
        internal static ContentTypeDefinition LuaContentType = null;

        [Export]
        [FileExtension(".lua")]
        [ContentType("LuaLanguageExtension")]
        internal static FileExtensionToContentTypeDefinition LuaFileType = null;

        [Import]
        internal IClassificationTypeRegistryService ClassificationTypeRegistry = null;

        [Import]
        internal IBufferTagAggregatorFactoryService aggregatorFactory = null;

        public ITagger<T> CreateTagger<T>(ITextBuffer buffer) where T : ITag
        {

            ITagAggregator<LuaTokenTag> luaTagAggregator = aggregatorFactory.CreateTagAggregator<LuaTokenTag>(buffer);

            return new LuaClassifier(buffer, luaTagAggregator, ClassificationTypeRegistry) as ITagger<T>;
        }
    }

    internal sealed class LuaClassifier : ITagger<ClassificationTag>
    {
        ITextBuffer buffer;
        ITagAggregator<LuaTokenTag> aggregator;
        IDictionary<LexemType, IClassificationType> luaTypes;

        internal LuaClassifier(ITextBuffer buf,
                               ITagAggregator<LuaTokenTag> luaTagAggregator,
                               IClassificationTypeRegistryService typeService)
        {
            buffer = buf;
            aggregator = luaTagAggregator;
            luaTypes = new Dictionary<LexemType, IClassificationType>();

            foreach (var item in Enum.GetValues(typeof(LexemType)))
            {
                IClassificationType clType = typeService.GetClassificationType("PSLib." + item.ToString());
                luaTypes[(LexemType)item] = clType;
            }
        }

        public event EventHandler<SnapshotSpanEventArgs> TagsChanged
        {
            add { }
            remove { }
        }

        public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans)
        {
            foreach (var tagSpan in this.aggregator.GetTags(spans))
            {
                var tagSpans = tagSpan.Span.GetSpans(spans[0].Snapshot);
                ClassificationTag tag = null;
                try
                {
                    IClassificationType clType = luaTypes[tagSpan.Tag.Lexem.Type];
                    tag = new ClassificationTag(clType);
                }
                catch (Exception)
                {
                    throw;
                }
                yield return new TagSpan<ClassificationTag>(tagSpans[0], tag);
            }
        }
    }
}
